﻿using NHibernate;
using SportStore.Core.Data;

namespace SportStore.Core.NHibernate
{
    /// <summary>
    /// Implements the generic transaction.
    /// </summary>
    public class Transaction : IGenericTransaction
    {
        #region Constants and Fields

        private readonly ITransaction transaction;

        /// <summary>
        /// The current reference count.
        /// </summary>
        private int referenceCount;

        /// <summary>
        /// The total number of times this transaction was referenced.
        /// </summary>
        private int totalReferences;

        /// <summary>
        /// The total number of times this transaction was committed. The overall transaction will only
        /// be completely committed when totalReferences == commitCount.
        /// </summary>
        private int commitCount;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="Transaction"/> class.
        /// </summary>
        public Transaction(ITransaction transaction)
        {
            this.transaction = transaction;
        }

        #endregion

        #region Internal Properties
        /// <summary>
        /// Gets a value indicating whether this instance has references to it, i.e. it is still active.
        /// </summary>
        internal bool HasReferences
        {
            get { return this.referenceCount > 0; }
        }
        #endregion

        #region Public Methods

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            this.referenceCount--;

            // Only *actually* dispose if the reference count has reached 0.
            if (this.referenceCount == 0)
            {
                this.transaction.Dispose();
            }
        }

        /// <summary>
        /// Commits the changes in the transaction.
        /// </summary>
        public void Commit()
        {
            this.commitCount++;
            if (this.referenceCount == 1)
            {
                // This is the last reference to the transaction
                if (this.commitCount == this.totalReferences)
                {
                    // All the references committed successfully
                    this.transaction.Commit();
                }
            }
        }
        #endregion

        #region Internal Methods

        /// <summary>
        /// Increments the reference count to this instance.
        /// </summary>
        public void IncrementReferenceCount()
        {
            this.referenceCount++;
            this.totalReferences++;
        }

        #endregion
    }
}
